package xty.rabbitmq.bean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Scope;
import xty.rabbitmq.enums.RabbitMQQueue;
import xty.util.ComponentUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * rabbitmq配置
 *
 * @author XieTianYi
 */
@Configuration
@DependsOn("springBeanUtil")
public class RabbitConfig {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${spring.rabbitmq.host}")
    private String host;

    @Value("${spring.rabbitmq.port}")
    private int port;

    @Value("${spring.rabbitmq.username}")
    private String username;

    @Value("${spring.rabbitmq.password}")
    private String password;

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setPublisherConfirms(true);
        return connectionFactory;
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    //必须是prototype类型
    public RabbitTemplate rabbitTemplate() {
        return new RabbitTemplate(connectionFactory());
    }

    /**
     * 针对消费者配置
     * 1. 设置交换机类型
     * 2. 将队列绑定到交换机
     * FanoutExchange: 将消息分发到所有的绑定队列，无routingkey的概念
     * HeadersExchange ：通过添加属性key-value匹配
     * DirectExchange:按照routingkey分发到指定队列
     * TopicExchange:多关键字匹配
     */
    public DirectExchange defaultExchange(String exchange) {
        return new DirectExchange(exchange);
    }

    /**
     * 获取队列A
     *
     * @return
     */
    public Queue queue(String queue) {
        return new Queue(queue, true); //队列持久
    }

    public void rabbitMQ() {
        for (RabbitMQQueue rabbitMQQueue : RabbitMQQueue.values()) {
            RabbitListener rabbitListener = (RabbitListener) rabbitMQQueue.getReceiveClass().getAnnotation(RabbitListener.class);

            try {
                Map<String, Object> values = ComponentUtil.getAnnotationMap(rabbitListener);
                String[] queues = (String[]) values.getOrDefault("queues", new String[]{});
                List<String> list = new ArrayList<>(Arrays.asList(queues));
                list.add(rabbitMQQueue.name());
                values.put("queues", list.toArray(queues));

                //将applicationContext转换为ConfigurableApplicationContext
                ComponentUtil.registerBean(rabbitMQQueue.getBindingName(), binding(rabbitMQQueue.name(), rabbitMQQueue.getExchange(),
                        rabbitMQQueue.getRouteKey()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    RabbitConfig() {
        rabbitMQ();
    }

    public Binding binding(String queue, String exchange, String routeKey) {
        return BindingBuilder.bind(queue(queue)).to(defaultExchange(exchange)).with(routeKey);
    }
}